package com.mdp.tpa.wechat.client.miniapp.login.service;

import com.mdp.core.entity.LangTips;
import com.mdp.core.entity.Result;
import com.mdp.core.utils.LogUtils;
import com.mdp.safe.client.jwt.JwtLocalLoginService;
import com.mdp.tpa.pub.entity.SysUser;
import com.mdp.tpa.pub.entity.SysUserTpa;
import com.mdp.tpa.wechat.util.WxaSecurityUtil;
import com.mdp.safe.client.dict.AuthType;
import com.mdp.tpa.pub.service.UserDataBaseService;
import com.mdp.core.entity.Tips;
import com.mdp.core.err.BizException;
import com.mdp.safe.client.entity.CommonUserDetails;
import com.mdp.safe.client.entity.User;
import com.mdp.safe.client.utils.LoginUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.core.endpoint.MapOAuth2AccessTokenResponseConverter;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;

import java.nio.charset.Charset;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Service
public class WechatMiniAppLoginHelpService {

    Logger logger = LoggerFactory.getLogger(WechatMiniAppLoginHelpService.class);

    @Autowired
    JwtLocalLoginService jwtLoginService;

    @Autowired
    ClientRegistrationRepository clientRegistrationRepository;


    @Autowired
    UserDataBaseService userService;


    MapOAuth2AccessTokenResponseConverter converter=new MapOAuth2AccessTokenResponseConverter();

    public Result loginByWechatMiniApp(String openid, String code, String userid, String phoneno, String unionid) {
         try {
            ClientRegistration client = clientRegistrationRepository.findByRegistrationId("client-login");
            Map<String,Object> params=new HashMap<>();
            params.put("userloginid",openid);//userid,openid,phoneno,email等

             params.put("userid",userid);//userid,openid,phoneno,email等
            params.put("password",code);//密码，短信验证码，微信登陆时对应的code等
            params.put("authType", AuthType.wechat_mini_app);//passwod，sms,email,wechat_mini_app等
            params.put("phoneno",phoneno);
            params.put("unionid",unionid);
            params.put("grantType","password");
            params.put("gloNo", LogUtils.getGloNo(true));//全局跟踪号
            ClientRegistration finalClient = client;
            Map messages = WebClient.create()
                    .post()
                    .uri(client.getProviderDetails().getTokenUri()+"?grant_type={grantType}&auth_type={authType}&userloginid={userloginid}&password={password}&userid={userid}&phoneno={phoneno}&unionid={unionid}&gloNo={gloNo}",params)
                    .headers(h->{
                        h.add("Authorization","Basic "+ Base64.getEncoder().encodeToString((finalClient.getClientId()+":"+ finalClient.getClientSecret()).getBytes(Charset.forName("UTF-8"))));
                    })
                    .retrieve()
                    .bodyToMono(Map.class)
                    .block();

            OAuth2AccessTokenResponse response=converter.convert(messages);
             Tips tips = jwtLoginService.doLocalLoginUseJwtToken(response.getAccessToken().getTokenValue());
             Result.assertIsFalse(tips);
             User user=LoginUtils.getCurrentUserInfo();
             CommonUserDetails userDetails=jwtLoginService.getUserDetails();
            return Result.ok().setData(response).put("userInfo",user).put("roles",userDetails.getAuthorities());
         }catch ( WebClientResponseException.Unauthorized e1){
             logger.error("账户密码错误",e1);
             return Result.error("accountId-or-password-error","账户或者密码错误").put("moreMsg",e1.getMessage());
         }catch (WebClientResponseException.InternalServerError e1){
             logger.error("服务器错误",e1);
             return Result.error("server-error","服务器错误").put("moreMsg",e1.getMessage());
         }catch (WebClientResponseException.BadGateway e1){
             logger.error("网关错误",e1);
             return Result.error("gate-error","网关错误").put("moreMsg",e1.getMessage());
         }catch (WebClientResponseException.BadRequest e1){
             logger.error("不正确的请求",e1);
             return Result.error("request-error","不正确的请求").put("moreMsg",e1.getMessage());
         }catch (BizException e1){
             logger.error("",e1);
             return Result.error(e1);
         }catch (Exception e1){
             logger.error("获取令牌错误",e1);
             return Result.error("get-token-error","获取令牌错误").put("moreMsg",e1.getMessage());
         }
    }

    public String getPhonenoFromParams(Map<String, Object> params,String sessionKey) {
        Tips tips = new Tips("解密手机正确");
        String   phonenoIv=(String)params.get("phonenoIv");
        String   phonenoEncryptedData=(String)params.get("phonenoEncryptedData");
        if(logger.isDebugEnabled()) {
            logger.debug("通过 检查客户端是否上送了手机号码的加密信息，如果上送，将调用解密服务获取手机号码  phonenoIv【"+phonenoIv+"】,phonenoEncryptedData【"+phonenoEncryptedData+"】");
        }
        if(!StringUtils.isEmpty(phonenoIv)&&!StringUtils.isEmpty(phonenoEncryptedData)) {

            try {
                Map<String,Object> phonenoInfo = WxaSecurityUtil.decrypt( sessionKey, phonenoEncryptedData, phonenoIv);
                logger.info("获取手机号码成功",phonenoInfo);
                return (String) phonenoInfo.get("phoneNumber");
            } catch (Exception e) {
                logger.error("解密手机号码错误",e);
                throw new BizException(LangTips.errMsg("decrypt-phoneno-err","解密手机号码错误"));

            }
        }
        return null;
    }
    @Transactional
    public SysUser autoRegisterByUserTpa(String inviteId, SysUserTpa userTpa, boolean tpadbExists){
        return userService.registerUserByTpa(inviteId,userTpa,tpadbExists);
    }


    public SysUserTpa wechatUserInfoConvertToUserTpa(Map<String,Object> wechatUserInfo){
        SysUserTpa tpa=new SysUserTpa();
        tpa.setUnionid((String) wechatUserInfo.get("unionid"));
        tpa.setOpenid((String) wechatUserInfo.get("openid"));
        tpa.setCountry((String) wechatUserInfo.get("country"));
        tpa.setUsername((String) wechatUserInfo.get("nickname"));
        tpa.setNickname((String) wechatUserInfo.get("nickname"));
        tpa.setProvince((String) wechatUserInfo.get("province"));
        tpa.setCity((String) wechatUserInfo.get("city"));
        tpa.setHeadimgurl((String) wechatUserInfo.get("headimgurl"));
        if(wechatUserInfo.containsKey("sex")){
             tpa.setGender(wechatUserInfo.get("sex")+"");
        }
        return tpa;
    }

}
